package com.develrage.prinance.soapws;

import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.xml.ws.RequestWrapper;
import javax.xml.ws.ResponseWrapper;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

@WebService(wsdlLocation = "PrinanceWS.wsdl", name = "PrinanceWS", targetNamespace = "http://soapws.prinance.develrage.com/PrinanceWS/")
public class PrinanceWSImpl implements PrinanceWS
{
    GeneralFaultImpl faults = new GeneralFaultImpl();

    // in-memory lists
    private List<Version> imVersionList;

    public PrinanceWSImpl()
    {
	imVersionList = new ArrayList<Version>();
	imVersionList.add(VersionImpl.getInstance("WS Definition XML",
		new BigDecimal("0.3"), "6-16"));
	imVersionList.add(VersionImpl.getInstance("WS Portable Artifacts",
		new BigDecimal(10.31), "6-16"));
	imVersionList.add(VersionImpl.getInstance("WS Server Implementation",
		new BigDecimal(0.3), "6-16"));

	// testing dbconnection
	SqlSession db = openDBConnection();
	System.out.println("Tested DB connection");
	db.close();
    }

    /*
     * Helper methods
     */

    private SqlSession openDBConnection()
    {
	String resource = "dbconnection-conf.xml";
	InputStream inputStream = null;
	try
	{
	    inputStream = Resources.getResourceAsStream(resource);
	} catch (IOException e)
	{
	    e.printStackTrace();
	}
	SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
		.build(inputStream);

	SqlSession sqlSession = sqlSessionFactory.openSession();
	return sqlSession;
    }

    private boolean isSetAndTrue(Boolean field)
    {
	return (field != null && field == true);
    }

    /*
     * Version
     */

    @Override
    @WebMethod(operationName = "GetVersion", action = "http://soapws.prinance.develrage.com/PrinanceWS/GetVersion")
    @WebResult(name = "Version", targetNamespace = "")
    @RequestWrapper(localName = "GetVersion", targetNamespace = "http://soapws.prinance.develrage.com/PrinanceWS/", className = "com.develrage.prinance.soapws.GetVersion")
    @ResponseWrapper(localName = "GetVersionResponse", targetNamespace = "http://soapws.prinance.develrage.com/PrinanceWS/", className = "com.develrage.prinance.soapws.GetVersionResponse")
    public List<Version> getVersion()
    {
	return imVersionList;
    }

    /*
     * Storage
     */

    @Override
    @WebMethod(operationName = "GetStorage", action = "http://soapws.prinance.develrage.com/PrinanceWS/GetStorage")
    @WebResult(name = "Storage", targetNamespace = "")
    @RequestWrapper(localName = "GetStorage", targetNamespace = "http://soapws.prinance.develrage.com/PrinanceWS/", className = "com.develrage.prinance.soapws.GetStorage")
    @ResponseWrapper(localName = "GetStorageResponse", targetNamespace = "http://soapws.prinance.develrage.com/PrinanceWS/", className = "com.develrage.prinance.soapws.GetStorageResponse")
    public List<Storage> getStorage(
	    @WebParam(name = "StorageFilter", targetNamespace = "") StorageFilter storageFilter)
    {

	List<Storage> resultset;
	StorageExample sqlselect = new StorageExample();

	com.develrage.prinance.soapws.StorageExample.Criteria where = new com.develrage.prinance.soapws.StorageExample.Criteria();

	if (storageFilter.storageFilterById != null)
	{
	    where.andStorageIdEqualTo(storageFilter.storageFilterById);
	}
	if (storageFilter.storageFilterByCode != null)
	{
	    where.andStorageCodeLike("%" + storageFilter.storageFilterByCode
		    + "%");
	}
	if (storageFilter.storageFilterByName != null)
	{
	    where.andStorageNameLike("%" + storageFilter.storageFilterByName
		    + "%");
	}
	if (storageFilter.storageFilterByIsActive != null)
	{
	    where.andStorageIsActiveEqualTo(storageFilter.storageFilterByIsActive);
	}
	if (storageFilter.storageFilterByIsOwned != null)
	{
	    where.andStorageIsOwnedEqualTo(storageFilter.storageFilterByIsOwned);
	}

	sqlselect.or(where);

	// TODO: add try-catch-exception
	SqlSession db = openDBConnection();
	StorageMapper mapper = db.getMapper(StorageMapper.class);
	resultset = mapper.selectByExample(sqlselect);
	db.close();

	return resultset;
    }

    @Override
    @WebMethod(operationName = "AlterStorage", action = "http://soapws.prinance.develrage.com/PrinanceWS/AlterStorage")
    @WebResult(name = "Storage", targetNamespace = "")
    @RequestWrapper(localName = "AlterStorage", targetNamespace = "http://soapws.prinance.develrage.com/PrinanceWS/", className = "com.develrage.prinance.soapws.AlterStorage")
    @ResponseWrapper(localName = "AlterStorageResponse", targetNamespace = "http://soapws.prinance.develrage.com/PrinanceWS/", className = "com.develrage.prinance.soapws.AlterStorageResponse")
    public Storage alterStorage(
	    @WebParam(name = "AlterStorage", targetNamespace = "") Storage alterStorage,
	    @WebParam(name = "StorageAlterSet", targetNamespace = "") StorageAlterSet storageAlterSet)
	    throws GeneralFaultException
    {
	SqlSession db;

	db = openDBConnection();

	StorageMapper mapper = db.getMapper(StorageMapper.class);

	if (isSetAndTrue(storageAlterSet.storageCode)
		|| isSetAndTrue(storageAlterSet.storageComment)
		|| isSetAndTrue(storageAlterSet.storageIsActive)
		|| isSetAndTrue(storageAlterSet.storageIsOwned)
		|| isSetAndTrue(storageAlterSet.storageName))
	{
	    if (!isSetAndTrue(storageAlterSet.storageName))
	    {
		// TODO: validate StorageName
		alterStorage.setStorageName(null);
	    }

	    if (!isSetAndTrue(storageAlterSet.storageCode))
	    {
		// TODO: validate StorageCode
		alterStorage.setStorageCode(null);
	    }

	    if (!isSetAndTrue(storageAlterSet.storageComment))
	    {
		alterStorage.setStorageComment(null);
	    }

	    if (!isSetAndTrue(storageAlterSet.storageIsActive))
	    {
		alterStorage.setStorageIsActive(null);
	    }

	    if (!isSetAndTrue(storageAlterSet.storageIsOwned))
	    {
		alterStorage.setStorageIsOwned(null);
	    }

	    // update
	    mapper.updateByPrimaryKeySelective(alterStorage);
	    db.commit();

	}
	// select
	alterStorage = mapper.selectByPrimaryKey(alterStorage.storageId);
	db.close();

	return alterStorage;

    }

    @Override
    @WebMethod(operationName = "NewStorage", action = "http://soapws.prinance.develrage.com/PrinanceWS/NewStorage")
    @WebResult(name = "Storage", targetNamespace = "")
    @RequestWrapper(localName = "NewStorage", targetNamespace = "http://soapws.prinance.develrage.com/PrinanceWS/", className = "com.develrage.prinance.soapws.NewStorage")
    @ResponseWrapper(localName = "NewStorageResponse", targetNamespace = "http://soapws.prinance.develrage.com/PrinanceWS/", className = "com.develrage.prinance.soapws.NewStorageResponse")
    public Storage newStorage(
	    @WebParam(name = "NewStorage", targetNamespace = "") Storage newStorage)
	    throws GeneralFaultException
    {
	SqlSession db = openDBConnection();
	StorageMapper mapper = db.getMapper(StorageMapper.class);

	newStorage.setStorageId(null);

	// TODO: validate newStorage
	mapper.insertSelective(newStorage);
	db.commit();

	newStorage = mapper.selectByPrimaryKey(newStorage.storageId);

	db.close();

	return newStorage;

    }

    /*
     * Plan
     */

    @Override
    @WebMethod(operationName = "NewPlan", action = "http://soapws.prinance.develrage.com/PrinanceWS/NewPlan")
    @WebResult(name = "Plan", targetNamespace = "")
    @RequestWrapper(localName = "NewPlan", targetNamespace = "http://soapws.prinance.develrage.com/PrinanceWS/", className = "com.develrage.prinance.soapws.NewPlan")
    @ResponseWrapper(localName = "NewPlanResponse", targetNamespace = "http://soapws.prinance.develrage.com/PrinanceWS/", className = "com.develrage.prinance.soapws.NewPlanResponse")
    public Plan newPlan(
	    @WebParam(name = "NewPlan", targetNamespace = "") Plan newPlan)
	    throws GeneralFaultException
    {
	SqlSession db = openDBConnection();
	PlanMapper mapper = db.getMapper(PlanMapper.class);

	newPlan.setPlanId(null);

	// TODO: validate newStorage
	mapper.insertSelective(newPlan);
	db.commit();

	newPlan = mapper.selectByPrimaryKey(newPlan.planId);

	db.close();

	return newPlan;

    }

    @Override
    @WebMethod(operationName = "GetPlan", action = "http://soapws.prinance.develrage.com/PrinanceWS/GetPlan")
    @WebResult(name = "Plan", targetNamespace = "")
    @RequestWrapper(localName = "GetPlan", targetNamespace = "http://soapws.prinance.develrage.com/PrinanceWS/", className = "com.develrage.prinance.soapws.GetPlan")
    @ResponseWrapper(localName = "GetPlanResponse", targetNamespace = "http://soapws.prinance.develrage.com/PrinanceWS/", className = "com.develrage.prinance.soapws.GetPlanResponse")
    public List<Plan> getPlan(
	    @WebParam(name = "PlanFilter", targetNamespace = "") PlanFilter planFilter)
    {
	List<Plan> resultset;
	PlanExample sqlselect = new PlanExample();
	com.develrage.prinance.soapws.PlanExample.Criteria where = new com.develrage.prinance.soapws.PlanExample.Criteria();

	if (planFilter.planFilterById != null)
	{
	    where.andPlanIdEqualTo(planFilter.planFilterById);
	}
	if (planFilter.planFilterByCode != null)
	{
	    where.andPlanCodeLike("%" + planFilter.planFilterByCode + "%");
	}
	if (planFilter.planFilterByName != null)
	{
	    where.andPlanNameLike("%" + planFilter.planFilterByName + "%");
	}
	if (planFilter.planFilterByIsActive != null)
	{
	    where.andPlanIsActiveEqualTo(planFilter.planFilterByIsActive);
	}

	sqlselect.or(where);

	// TODO: add try-catch-exception
	SqlSession db = openDBConnection();
	PlanMapper mapper = db.getMapper(PlanMapper.class);
	resultset = mapper.selectByExample(sqlselect);
	db.close();

	return resultset;
    }

    @Override
    @WebMethod(operationName = "AlterPlan", action = "http://soapws.prinance.develrage.com/PrinanceWS/AlterPlan")
    @WebResult(name = "Plan", targetNamespace = "")
    @RequestWrapper(localName = "AlterPlan", targetNamespace = "http://soapws.prinance.develrage.com/PrinanceWS/", className = "com.develrage.prinance.soapws.AlterPlan")
    @ResponseWrapper(localName = "AlterPlanResponse", targetNamespace = "http://soapws.prinance.develrage.com/PrinanceWS/", className = "com.develrage.prinance.soapws.AlterPlanResponse")
    public Plan alterPlan(
	    @WebParam(name = "AlterPlan", targetNamespace = "") Plan alterPlan,
	    @WebParam(name = "PlanAlterSet", targetNamespace = "") PlanAlterSet planAlterSet)
	    throws GeneralFaultException
    {
	SqlSession db;

	db = openDBConnection();

	PlanMapper mapper = db.getMapper(PlanMapper.class);

	if (isSetAndTrue(planAlterSet.planCode)
		|| isSetAndTrue(planAlterSet.planComment)
		|| isSetAndTrue(planAlterSet.planIsActive)
		|| isSetAndTrue(planAlterSet.planName))
	{
	    if (!isSetAndTrue(planAlterSet.planName))
	    {
		// TODO: validate PlanName
		alterPlan.setPlanName(null);
	    }

	    if (!isSetAndTrue(planAlterSet.planCode))
	    {
		// TODO: validate PlanCode
		alterPlan.setPlanCode(null);
	    }

	    if (!isSetAndTrue(planAlterSet.planComment))
	    {
		alterPlan.setPlanComment(null);
	    }

	    if (!isSetAndTrue(planAlterSet.planIsActive))
	    {
		alterPlan.setPlanIsActive(null);
	    }

	    // update
	    mapper.updateByPrimaryKeySelective(alterPlan);
	    db.commit();

	}
	// select
	alterPlan = mapper.selectByPrimaryKey(alterPlan.planId);
	db.close();

	return alterPlan;
    }

    /*
     * Collection
     */

    @Override
    @WebMethod(operationName = "NewCollection", action = "http://soapws.prinance.develrage.com/PrinanceWS/NewCollection")
    @WebResult(name = "Collection", targetNamespace = "")
    @RequestWrapper(localName = "NewCollection", targetNamespace = "http://soapws.prinance.develrage.com/PrinanceWS/", className = "com.develrage.prinance.soapws.NewCollection")
    @ResponseWrapper(localName = "NewCollectionResponse", targetNamespace = "http://soapws.prinance.develrage.com/PrinanceWS/", className = "com.develrage.prinance.soapws.NewCollectionResponse")
    public Collection newCollection(
	    @WebParam(name = "unused", targetNamespace = "") String unused)
    {
	SqlSession db = openDBConnection();
	CollectionMapper mapper = db.getMapper(CollectionMapper.class);

	Collection newCollection = new Collection();
	newCollection.setCollectionId(null);

	mapper.insert(newCollection);
	db.commit();

	// List<Collection> resultset;
	// CollectionExample sqlselect = new CollectionExample();
	// com.develrage.prinance.soapws.CollectionExample.Criteria where = new
	// com.develrage.prinance.soapws.CollectionExample.Criteria();
	// where.andCollectionIdEqualTo(newCollection.collectionId);
	// sqlselect.or(where);
	//
	// resultset = mapper.selectByExample(sqlselect);
	// newCollection = resultset.get(0);

	db.close();

	return newCollection;
    }

    /*
     * Movement
     */

    @Override
    @WebMethod(operationName = "NewMovement", action = "http://soapws.prinance.develrage.com/PrinanceWS/NewMovement")
    @WebResult(name = "Movement", targetNamespace = "")
    @RequestWrapper(localName = "NewMovement", targetNamespace = "http://soapws.prinance.develrage.com/PrinanceWS/", className = "com.develrage.prinance.soapws.NewMovement")
    @ResponseWrapper(localName = "NewMovementResponse", targetNamespace = "http://soapws.prinance.develrage.com/PrinanceWS/", className = "com.develrage.prinance.soapws.NewMovementResponse")
    public Movement newMovement(
	    @WebParam(name = "NewMovement", targetNamespace = "") Movement newMovement)
    {
	SqlSession db = openDBConnection();
	MovementMapper mapper = db.getMapper(MovementMapper.class);

	newMovement.setMvmId(null);

	// TODO: validate newMovement
	// TODO: use stored procedure to work around null-CollectionId
	mapper.insertSelective(newMovement);
	db.commit();

	newMovement = mapper.selectByPrimaryKey(newMovement.mvmId);

	db.close();

	return newMovement;
    }

    @Override
    @WebMethod(operationName = "GetMovement", action = "http://soapws.prinance.develrage.com/PrinanceWS/GetMovement")
    @WebResult(name = "Movement", targetNamespace = "")
    @RequestWrapper(localName = "GetMovement", targetNamespace = "http://soapws.prinance.develrage.com/PrinanceWS/", className = "com.develrage.prinance.soapws.GetMovement")
    @ResponseWrapper(localName = "GetMovementResponse", targetNamespace = "http://soapws.prinance.develrage.com/PrinanceWS/", className = "com.develrage.prinance.soapws.GetMovementResponse")
    public List<Movement> getMovement(
	    @WebParam(name = "MovementFilter", targetNamespace = "") MovementFilter movementFilter)
    {
	List<Movement> resultset = new ArrayList<Movement>();
	MovementExample sqlselect = new MovementExample();

	com.develrage.prinance.soapws.MovementExample.Criteria where = new com.develrage.prinance.soapws.MovementExample.Criteria();

	// byId
	if (movementFilter.mvmFilterById != null)
	{
	    where.andMvmIdEqualTo(movementFilter.mvmFilterById);
	}
	// byCollectionId
	if (movementFilter.mvmFilterByCollectionId != null)
	{
	    where.andMvmCollectionIdEqualTo(movementFilter.mvmFilterByCollectionId);
	}
	// byTarget/Source/Plan/Storage
	if (movementFilter.mvmFilterByStorageSource != null)
	{
	    where.andMvmStorageSourceEqualTo(movementFilter.mvmFilterByStorageSource);
	}
	if (movementFilter.mvmFilterByStorageTarget != null)
	{
	    where.andMvmStorageTargetEqualTo(movementFilter.mvmFilterByStorageTarget);
	}
	if (movementFilter.mvmFilterByPlanSource != null)
	{
	    where.andMvmPlanSourceEqualTo(movementFilter.mvmFilterByPlanSource);
	}
	if (movementFilter.mvmFilterByPlanTarget != null)
	{
	    where.andMvmPlanTargetEqualTo(movementFilter.mvmFilterByPlanTarget);
	}
	// byComment
	if (movementFilter.mvmFilterByComment != null)
	{
	    where.andMvmCommentLike("%" + movementFilter.mvmFilterByComment
		    + "%");
	}
	// byIsActive
	if (movementFilter.mvmFilterByIsActive != null)
	{
	    where.andMvmIsActiveEqualTo(movementFilter.mvmFilterByIsActive);
	}
	// byIsCommitted
	if (movementFilter.mvmFilterByIsCommitted != null)
	{
	    where.andMvmIsCommittedEqualTo(movementFilter.mvmFilterByIsCommitted);
	}
	// byAmountMin/Max
	if (movementFilter.mvmFilterByAmountMin != null)
	{
	    where.andMvmAmountGreaterThanOrEqualTo(movementFilter.mvmFilterByAmountMin);
	}
	if (movementFilter.mvmFilterByAmountMax != null)
	{
	    where.andMvmAmountLessThanOrEqualTo(movementFilter.mvmFilterByAmountMax);
	}
	// byDateFrom/To
	if (movementFilter.mvmFilterByDateFrom != null)
	{
	    // where.andMvmDatePlacedGreaterThanOrEqualTo(movementFilter.mvmFilterByDateFrom);
	    java.util.Date value = movementFilter.mvmFilterByDateFrom;
	    java.sql.Date d1 = new java.sql.Date(value.getTime());
	    where.addCriterion(String
		    .format("(mvmDatePlaced >= '%s' or mvmDateSource >= '%s' or mvmDateTarget >= '%s')",
			    d1, d1, d1));
	}
	if (movementFilter.mvmFilterByDateTo != null)
	{
	    // where.andMvmDatePlacedLessThanOrEqualTo(movementFilter.mvmFilterByDateTo);
	    java.util.Date value = movementFilter.mvmFilterByDateTo;
	    java.sql.Date d1 = new java.sql.Date(value.getTime());
	    where.addCriterion(String
		    .format("(mvmDatePlaced <= '%s' or mvmDateSource <= '%s' or mvmDateTarget <= '%s')",
			    d1, d1, d1));
	}

	sqlselect.or(where);
	sqlselect.setOrderByClause("mvmDatePlaced ASC");

	// TODO: add try-catch-exception
	SqlSession db = openDBConnection();
	ExtendedMovementMapper mapper = db
		.getMapper(ExtendedMovementMapper.class);
	resultset = mapper.selectByExampleLimited(sqlselect);
	db.close();

	return resultset;
    }

    @Override
    @WebMethod(operationName = "AlterMovement", action = "http://soapws.prinance.develrage.com/PrinanceWS/AlterMovement")
    @WebResult(name = "Movement", targetNamespace = "")
    @RequestWrapper(localName = "AlterMovement", targetNamespace = "http://soapws.prinance.develrage.com/PrinanceWS/", className = "com.develrage.prinance.soapws.AlterMovement")
    @ResponseWrapper(localName = "AlterMovementResponse", targetNamespace = "http://soapws.prinance.develrage.com/PrinanceWS/", className = "com.develrage.prinance.soapws.AlterMovementResponse")
    public Movement alterMovement(
	    @WebParam(name = "AlterMovement", targetNamespace = "") Movement alterMovement,
	    @WebParam(name = "MovementAlterSet", targetNamespace = "") MovementAlterSet movementAlterSet)
    {
	SqlSession db = openDBConnection();

	MovementMapper mapper = db.getMapper(MovementMapper.class);

	if (isSetAndTrue(movementAlterSet.mvmAmount)
		|| isSetAndTrue(movementAlterSet.mvmComment)
		|| isSetAndTrue(movementAlterSet.mvmIsActive)
		|| isSetAndTrue(movementAlterSet.mvmIsCommitted)
		|| isSetAndTrue(movementAlterSet.mvmCollectionId)
		|| isSetAndTrue(movementAlterSet.mvmPlanSource)
		|| isSetAndTrue(movementAlterSet.mvmPlanTarget)
		|| isSetAndTrue(movementAlterSet.mvmStorageSource)
		|| isSetAndTrue(movementAlterSet.mvmStorageTarget)
		|| isSetAndTrue(movementAlterSet.mvmDatePlaced)
		|| isSetAndTrue(movementAlterSet.mvmDateTarget)
		|| isSetAndTrue(movementAlterSet.mvmDateSource))
	{

	    // TODO: validate members which should be validated :)

	    if (!isSetAndTrue(movementAlterSet.mvmCollectionId))
	    {
		alterMovement.setMvmCollectionId(null);
	    }

	    if (!isSetAndTrue(movementAlterSet.mvmAmount))
	    {
		alterMovement.setMvmAmount(null);
	    }

	    if (!isSetAndTrue(movementAlterSet.mvmComment))
	    {
		alterMovement.setMvmComment(null);
	    }

	    if (!isSetAndTrue(movementAlterSet.mvmIsActive))
	    {
		alterMovement.setMvmIsActive(null);
	    }

	    if (!isSetAndTrue(movementAlterSet.mvmIsCommitted))
	    {
		alterMovement.setMvmIsCommitted(null);
	    }

	    if (!isSetAndTrue(movementAlterSet.mvmPlanSource))
	    {
		alterMovement.setMvmPlanSource(null);
	    }

	    if (!isSetAndTrue(movementAlterSet.mvmPlanTarget))
	    {
		alterMovement.setMvmPlanTarget(null);
	    }

	    if (!isSetAndTrue(movementAlterSet.mvmStorageSource))
	    {
		alterMovement.setMvmStorageSource(null);
	    }

	    if (!isSetAndTrue(movementAlterSet.mvmStorageTarget))
	    {
		alterMovement.setMvmStorageTarget(null);
	    }

	    if (!isSetAndTrue(movementAlterSet.mvmDatePlaced))
	    {
		alterMovement.setMvmDatePlaced(null);
	    }

	    if (!isSetAndTrue(movementAlterSet.mvmDateTarget))
	    {
		alterMovement.setMvmDateTarget(null);
	    }

	    if (!isSetAndTrue(movementAlterSet.mvmDateSource))
	    {
		alterMovement.setMvmDateSource(null);
	    }

	    // update
	    mapper.updateByPrimaryKeySelective(alterMovement);
	    db.commit();

	}
	// select
	alterMovement = mapper.selectByPrimaryKey(alterMovement.mvmId);
	db.close();

	return alterMovement;
    }
}
